package scoutobahn.ui;

import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.LinkedList;

import javax.swing.JFileChooser;
import javax.swing.JOptionPane;
import javax.swing.filechooser.FileFilter;
import javax.swing.text.JTextComponent;
import javax.xml.parsers.ParserConfigurationException;

import org.xml.sax.SAXException;

import scoutobahn.dijkstra.DijkstraNode;
import scoutobahn.highway.Highway;
import scoutobahn.highway.HighwayGraph;
import scoutobahn.highway.Town;
import scoutobahn.util.Tuple;
import scoutobahn.xml.HighwayGraphBuilder;
import scoutobahn.xml.OsmNode;
import scoutobahn.xml.XmlTownLoader;

/**
 * Controller Class, managing View and Model.
 * @author Florian
 */
public class Controller {
    private Model model;
    private static View view;
    private final long townNodeDistance = 50000;

    /**
     * Starts the application by creating View and Model , then starting the
     * eventqueue for the View.
     */
    public void startApp() {
        model = new Model();
        view = new View();

        view.getjButtonStart().addActionListener(
                new java.awt.event.ActionListener() {
                    public void actionPerformed(
                            final java.awt.event.ActionEvent evt) {
                        jButtonStartActionPerformed(evt);
                    }
                });

        model.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(final java.awt.event.ActionEvent evt) {
                fillViewWithRouteData((Model) evt.getSource());
            }
        });

        view.addWindowListener(new java.awt.event.WindowAdapter() {
            public void windowOpened(final java.awt.event.WindowEvent evt) {
                formWindowOpened(evt);
            }
        });

        java.awt.EventQueue.invokeLater(new Runnable() {
            public void run() {
                view.setVisible(true);
            }
        });

    }

    /**
     * Converts the eventsource to its original type and lets the view display
     * the data stored within.
     * @param source
     *            The result of the dijkstra algorithm.
     */
    protected void fillViewWithRouteData(final Model source) {
        Collection<Tuple<Double, Double>> coordinates =
                new LinkedList<Tuple<Double, Double>>();
        Collection<String> highways = new LinkedList<String>();
        if (source.getNodes().isEmpty()) {
            JOptionPane.showMessageDialog(view, "Keine Route gefunden");
            return;
        }
        for (DijkstraNode node : source.getNodes()) {
            coordinates.add(new Tuple<Double, Double>(
                    node.getHighwayNode().getOsmItem().getLatitude(),
                    node.getHighwayNode().getOsmItem().getLongitude()));
            if (node.getHighway() != null) {
               highways.add(node.getHighway().getOsmItem().getTag("ref"));
            }
        }
        view.addMapPoints(coordinates);
        view.addHighwayList(highways);
    }

    private HighwayGraph loadHighwayGraph() throws SAXException, IOException,
            ParserConfigurationException {
        JFileChooser highwayXmlChooser = new JFileChooser();
        JFileChooser townXmlChooser = new JFileChooser();
        highwayXmlChooser.setDialogTitle("Autobahndaten ausw�hlen");
        townXmlChooser.setDialogTitle("Stadtdaten ausw�hlen");
        highwayXmlChooser.setCurrentDirectory(new File(System
                .getProperty("user.dir")));
        townXmlChooser.setCurrentDirectory(new File(System
                .getProperty("user.dir")));
        FileFilter xmlFileFilter = new FileFilter() {

            @Override
            public boolean accept(final File f) {
                if (f.toURI().toString().endsWith(".xml")) {
                    return true;
                }
                return false;
            }

            @Override
            public String getDescription() {
                return "XML-Dateien";
            }
        };
        highwayXmlChooser.setFileFilter(xmlFileFilter);
        townXmlChooser.setFileFilter(xmlFileFilter);
        if (highwayXmlChooser.showOpenDialog(view)
                == JFileChooser.APPROVE_OPTION) {
            String highwayXml = highwayXmlChooser.getSelectedFile()
                    .getCanonicalPath();
            if (townXmlChooser.showOpenDialog(view)
                    == JFileChooser.APPROVE_OPTION) {
                String townXml = townXmlChooser.getSelectedFile()
                        .getCanonicalPath();
                Collection<OsmNode> townNodes = new XmlTownLoader()
                        .loadTowns(new FileInputStream(townXml));
                HighwayGraphBuilder builder = new HighwayGraphBuilder();
                HighwayGraph graph = builder.buildFromXml(new FileInputStream(
                        highwayXml), townNodes, townNodeDistance);
                return graph;
            }
        }
        return new HighwayGraph(new ArrayList<Highway>(),
                new ArrayList<Town>());
    }

    private void jButtonStartActionPerformed(
            final java.awt.event.ActionEvent evt) {
        view.removeMapPoints();
        model.runDijkstra(view.getjComboBoxFromTown().getSelectedItem()
                .toString(), view.getjComboBoxToTown().getSelectedItem()
                .toString());

    }

    private void formWindowOpened(final java.awt.event.WindowEvent evt) {
        JTextComponent editor = (JTextComponent) view.getjComboBoxFromTown()
                .getEditor().getEditorComponent();
        editor.setDocument(new AutoCompletionDocument(view
                .getjComboBoxFromTown()));
        editor = (JTextComponent) view.getjComboBoxToTown().getEditor()
                .getEditorComponent();
        editor.setDocument(new AutoCompletionDocument(view
                .getjComboBoxToTown()));

        try {
            model.setHighwayGraph(loadHighwayGraph());
        } catch (Exception e) {
            JOptionPane.showMessageDialog(view, e.toString()
                    + "/n/n Das Programm wird sich nun beenden. "
                    + "Bitte überprüfen Sie die Validität der "
                    + "angegebenen Dateien und versuchen Sie es erneut.",
                    "Fehler beim Laden der Kartendaten", JOptionPane.OK_OPTION);
            System.exit(1);
        }

        Collection<Town> townCollection = model.getHighwayGraph().getTowns();
        LinkedList<String> towns = new LinkedList<String>();
        for (Town town : townCollection) {
            towns.add(town.getOsmItem().getTag("name"));
        }
        Collections.sort(towns);
        for (String town : towns) {
            view.getjComboBoxFromTown().addItem(town);
            view.getjComboBoxToTown().addItem(town);
        }
    }
}
